#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <sys/timeb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h> // file option
#include <dirent.h>
// #include <iostream>
// #include <sstream>
// #include <vector>
// #include <list>
// #include <map>
// #include <thread>
// #include <string>
// #include <iomanip>
// #include <fstream>
// #include <vector>
// #include <set>
// #include <algorithm>
// #include <unordered_map>
// #include <mutex>
// #include <atomic>
// #include <bits/wordsize.h>
// #include <bits/timesize.h>
using namespace std;

//1、定义结构体方式千千万，我建议根据以下来定义。
//2、对其方式：根据最大数据类型分段。下面这个studentInfo结构体，weight占一字节，然后id为4字节，会导致weight占4字节来与id对其。除非使用#pragma pack(1)用1字节对其。
//          对其最终为最下类型长度的整数倍。
//3、大小端。比如short a = 0x1234;大端内存保存0x12,0x34,小端保存0x34，0x12。
//4、结构体变量，要看成一个int变量一样的东西，比如函数形参-实参同样是两个值。结构体指针，指针+1将指向下一个结构体首地址。
//5、备注，#pragma pack(1)中的结构体中不能使用std::string c++变量，可能会导致崩溃。
// #pragma pack(1)
struct studentInfo
{
    char weight;
    int id;
    short age;
    int height;
    short mathScore;
    char name[4];
};
// #pragma pack()

#pragma pack(1)
struct teacherInfo
{
    char weight;
    int id;
    short age;
    int height;
    short mathScore;
};
#pragma pack()

//枚举。V1=0，V2没有指定则在上一个基础上+1，V5指定100
enum studentStepEnum
{
    STD_STEP_V1 = 0,
    STD_STEP_V2,
    STD_STEP_V3,
    STD_STEP_V4,
    STD_STEP_V5 = 100,
    STD_STEP_MAX
};

//此结构体有两个特殊用法，指定bits数，联合体。
//其中a占1bit，b占2bit，c占4bit，因为他们可以共占7bit，因此放在同一字节中
//而d占4位，1字节放不下了，d会放在新字节中。
//联合体e,f,g,h占用同一空间，以最大的h为大小。
struct testStruct2
{
    int8_t a : 1;
    int8_t b : 2;
    int8_t c : 4;
    int8_t d : 4;
    union
    {
        int8_t e;
        short f;
        int g;
        long h;
    };
};


//typedef 用于定义一个类型。这里定义一个结构体babyInfo；定义一个类型babyInf1，他表示结构体babyInfo。
//不建议。
typedef struct babyInfo
{
    char wt;
    int id;
    short weight;
} babyInf1;

//这里的babyVal是一个结构体变量了，并且是全局变量。
//不建议。
struct babyInfo1
{
    char wt;
    int id;
    short weight;
} babyVal;

int main()
{
    struct studentInfo tmpsi;
    memset(&tmpsi, 0, sizeof(tmpsi));
    tmpsi.weight = 1;
    tmpsi.id = 0x1234;
    tmpsi.age = 3;
    tmpsi.height = 4;
    tmpsi.mathScore = 5;
    tmpsi.name[0] = 6;
    tmpsi.name[1] = 7;
    tmpsi.name[2] = 9;
    tmpsi.name[3] = 0x0a;

    struct teacherInfo tmpti;
    tmpti.weight = 1;
    tmpti.id = 0x123456;
    tmpti.age = 3;
    tmpti.height = 4;
    tmpti.mathScore = 5;

    babyInf1 tmpbaby;
    memset(&tmpbaby, 0, sizeof(tmpbaby));

    memset(&babyVal, 0, sizeof(babyVal));

    //长度为16，联合体是8字节，前面2字节需要对其会空出6字节
    printf("%d\n", (int)sizeof(struct testStruct2));

    char *tmpp = (char *)&tmpsi;
    //输出结果是：
    // student memery info:24
    // 0x01 0x00 0x00 0x00 0x34 0x12 0x00 0x00 0x03 0x00 0x00 0x00 0x04 0x00 0x00 0x00 0x05 0x00 0x06 0x07 0x09 0x0a 0x00 0x00 
    //1、对其方式。长度为24是因为对其方式的原因。tmpsi.weight需要与id对其，占了4个字节，tmpsi.age占了4字节，因为tmpsi.mathScore2字节，tmpsi.name[0]只有1个直接，
    //因此tmpsi.name[0]紧接着tmpsi.mathScore2排放。最终需要INT长度整数倍，最后空着2字节。
 
    //2、大小端。因为我的系统是小端。因此打印0x1234显示出来是0x34,0x12,0x00,0x00
    printf("student memery info:%d\n", (int)sizeof(tmpsi));
    for(int i = 0; i < (int)sizeof(tmpsi); i++)
    {
        printf("0x%02x ", tmpp[i]);
    }
    printf("\n");

    //teacher取消对其所以长度位13.但是还是遵循小端模式。
    tmpp = (char *)&tmpti;
    printf("teacher memery info:%d\n", (int)sizeof(tmpti));
    for(int i = 0; i < (int)sizeof(tmpti); i++)
    {
        printf("0x%02x ", tmpp[i]);
    }
    printf("\n");

    return 0;
}
//运行结果
// student memery info:24
// 0x01 0x00 0x00 0x00 0x34 0x12 0x00 0x00 0x03 0x00 0x00 0x00 0x04 0x00 0x00 0x00 0x05 0x00 0x06 0x07 0x09 0x0a 0x00 0x00 
// teacher memery info:13
// 0x01 0x56 0x34 0x12 0x00 0x03 0x00 0x04 0x00 0x00 0x00 0x05 0x00 

